﻿// CompositeKorean.cpp: implementation of the CCompositeKorean class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CompositeKorean.h"
#include "string.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CComposeKorU::CComposeKorU(void)
{
	//ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (총 30가지 경우)
	//ㄱㄲㅡㄴㅡㅡㄷㄸㄹㅡㅡㅡㅡㅡㅡㅡㅁㅂㅃㅡㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (총 19가지 경우)
	//ㄱ: 0xa4a1, ㅎ:0xa4be
	static signed char i1stKorChar[] = {0, 1, -1, 2, -1, -1, 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, 6, 7, 8, -1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
	//ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ
	//ㅏ: 0xa4bf, ㅣ:0xa4d3
	//int i2ndChar[] = {}; 이건 필요 없넹. 21개란 것만 알면 됨
	//ㄱㄲㄳㄴㄵㄶㄷㅡㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅡㅄㅅㅆㅇㅈㅡㅊㅋㅌㅍㅎ (받침이 없는 경우 제외하면 27가지, 없는 경우 포함하면 28가지)
	//ㄱ: 0xa4a1, ㅎ:0xa4be
	static signed char i3rdKorChar[] = {0, 1, 2, 3, 4, 5, 6, -1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, 22, 23, 24, 25, 26};

	i1stCharTable = i1stKorChar;
	i3rdCharTable = i3rdKorChar;
}

CComposeKorU::~CComposeKorU(void) {}

int CComposeKorU::iPosIn1st(WCHAR w, BOOL U1100Only)
{
	// 초중종 위치 보존 자모
	// U+1100~U+1112 ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (19)
	//
	// 초중종 위치 미보존 자모
	// U+3131~U+314E ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (30)

	if (w>=0x1100 && w<=0x1112) return (w-0x1100);
	if (!U1100Only && w>=0x3131 && w<=0x314e) {
		return i1stCharTable[w-0x3131];
	}

	return -1;
}

int CComposeKorU::iPosIn2nd(WCHAR w, BOOL U1100Only)
{
	// 초중종 위치 보존 자모
	// U+1161~U+1175 ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ (21)
	//
	// 초중종 위치 미보존 자모
	// U+314F~U+3163 ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ (21)

	if (w>=0x1161 && w<=0x1175) return (w-0x1161);
	if (!U1100Only && w>=0x314f && w<=0x3163) return (w-0x314f);

	return -1;
}


int CComposeKorU::iPosIn3rd(WCHAR w, BOOL U1100Only)
{
	// 초중종 위치 보존 자모
	// U+11A8~U+11C2 ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ (27, 없는 경우 미포함)
	//
	// 초중종 위치 미보존 자모
	// U+3131~U+314E ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (30)

	if (w>=0x11a8 && w<=0x11c2) return (w-0x11a8);
	if (!U1100Only && w>=0x3131 && w<=0x314e) {
		return i3rdCharTable[w-0x3131];
	}

	return -1;
}


// 첫 두 글자가 초성+중성 조합인가 확인
bool CComposeKorU::bIsFirst2Available(WCHAR * w, BOOL U1100Only)
{
	if (iPosIn1st(*w, U1100Only) < 0) return false;
	return (iPosIn2nd(w[1], U1100Only) >= 0);
}


// 초성+중성 → 한 글자
WCHAR CComposeKorU::Composite2(WCHAR * wSrc, BOOL U1100Only)
{
	// <조합결과>
	//
	// 초성: ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (19)
	// 중성: ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ (21)
	// 종성: xㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ (28, 없는 경우 포함)
	// U+AC00: 가

	int i1 = iPosIn1st(*wSrc, U1100Only);
	int i2 = iPosIn2nd(wSrc[1], U1100Only);
	if (i1<0 || i2<0) return 0x0020;

	return 0xac00 + i1*21*28 + i2*28;
}

// 초성+중성+종성 → 한 글자
WCHAR CComposeKorU::Composite3(WCHAR * wSrc, BOOL U1100Only)
{
	// <조합결과>
	//
	// 초성: ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ (19)
	// 중성: ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ (21)
	// 종성: xㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ (28, 없는 경우 포함)
	// U+AC00: 가

	int i1 = iPosIn1st(*wSrc, U1100Only);
	int i2 = iPosIn2nd(wSrc[1], U1100Only);
	int i3 = iPosIn3rd(wSrc[2], U1100Only);
	if (i1<0 || i2<0) return 0x0020;
	if (i3<0) return Composite2(wSrc, U1100Only);

	return 0xac00 + i1*21*28 + i2*28 + i3 + 1;
}


WCHAR * CComposeKorU::CompositeUniStr(WCHAR * wstr, BOOL U1100Only)
{
	int iLen = wcslen(wstr);
	WCHAR *result = new WCHAR[iLen+1];

	int iSrc = 0, iDst = 0;

	while (iSrc < iLen) {
		if (!wstr[iSrc]) break;
		if (bIsFirst2Available(wstr+iSrc, U1100Only)) {
			if (iPosIn3rd(wstr[iSrc+2], U1100Only)<0 || bIsFirst2Available(wstr+iSrc+2, U1100Only)) {
				result[iDst++] = Composite2(wstr+iSrc, U1100Only);
				iSrc+=2;
			} else {
				result[iDst++] = Composite3(wstr+iSrc, U1100Only);
				iSrc+=3;
			}
		} else {
			result[iDst++] = wstr[iSrc++];
		}
	}
	result[iDst] = 0;

	return result;
}
